package club.jdiy.core.sql;

import club.jdiy.core.base.domain.Pager;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;

/**
 * JDiy数据库操作DAO对象.
 *
 *
 * @author ziquee(子秋) QQ号:39886616 主页: http://www.jdiy.club
 * @version 20200218
 */
public interface Dao {

    /**
     * 根据指定条件返回数据库中的记录条数.
     *
     * @param args 查询参数对象，此对象至少需要设置好table属性。
     * @return 根据给定的参数条件查询并返回的数据库记录条数.
     */
    int len(Args args);

    /**
     * 到数据库中查询并返回单条记录.
     * <br >　　如果查询到的记录不止一条,此方法将返回该记录集的第一条数据.<br />
     * 　　如果查不到任何数据，将创建一个瞬时状态的Rs对象返回
     * (可以通过Rs对象的isNull()方法来检测该Dat对象是否为瞬时状态).
     *
     * @param args 查询参数对象，此对象至少需要设置好table属性。
     * @return 查询出来的单条记录封包的Rs对象，或瞬时的Rs对象
     * @see #rs(String)
     * @see #ls(Args)
     * @see Rs
     */
    Rs rs(Args args);

    Rs create(String table);

    Rs rs(String table, String id);

    Rs rs(String table, Number id);

    @Transactional
    Rs rs(String table, String id, String columns);

    @Transactional
    Rs rs(String table, Number id, String columns);

    /**
     * 根据原生SQL查询语句返回单条记录.
     * <br >　　如果查询到的记录不止一条,此方法将返回该记录集的第一条数据.<br />
     * 　　如果查不到任何数据，将创建一个瞬时状态的Rs对象返回
     * (可以通过Rs对象的isNull()方法来检测该Dat对象是否为瞬时状态).
     *
     * @param sql 原生SQL查询语句
     * @return 查询出来的单条记录封包的Rs对象，或瞬时的Rs对象
     * @see #ls(String, int, int)
     * @since 这是JDiy-1.12及后续版本新增的方法.
     */
    Rs rs(String sql);


    /**
     * 删除数据库中的记录,并将此Rs对象标记为瞬时状态. <br />
     *
     * @param rs 要删除的Rs对象.
     *           <br />此方法在删除数据库记录的同时,会连同附加在此对象上的XML字段及文件字段一并删除.
     * @return int 返回成功执行删除的记录数.
     * 通常情况下返回值都应该是1.
     * <br />如果返回值大于1,可能Rs对象的主键信息设置有误;<br />
     * 如果返回值为0,则表示Dat对象所指向的数据库记录不存在或在此之前已经被删除.
     * @see #del(Args)
     */
    int del(Rs rs);

    /**
     * 根据给定的查询条件删除数据库中的记录.  <br />
     *
     * @param args 删除操作的条件参数，该参数必须指定table, filter属性.
     * @return int 返回成功执行删除的记录数.
     * @see #del(Rs)
     */
    int del(Args args);


    /**
     * 根据原生SQL语句执行更新(UPDATE, INSERT等等). <br />
     * 　　当然也可以使用此方法执行删除(DELETE)操作，但如果要操作的数据对象通过JDiy附加了一些XML/文件附件字段,
     * 系统建议您用{@link #del(Rs)}或{@link #del(Args)}执行删除, 以便相关的XML/文件能够同时被移除.
     *
     * @param sql SQL语句。
     * @return int 返回成功执行的记录数.
     */
    int exec(String sql);

    /**
     * 根据给定的SQL查询语句返回Ls记录集对象. 此方法适用于非常复杂的SQL查询语句.<br />
     * <strong>特别注意：</strong>如果可以，最好使用{@link #ls(Args)}方法进行查询，以获得更好的查询效率(MsSQL除外)。<br/>
     * 另外， 受某些数据库驱动程序的限制（例如Oracle）,或者指定的SQL语句是一个非常复杂的查询，
     * 您可能无法从Rs结果中取到正确的表名信息（通过{@link Rs#getTable()}方法可以取得表名），
     * 除非您明确Rs对象的表名信息，建议尽量少将Rs对象修改后再进行持久化，以免产生不可预知的错误。
     *
     * @param sql      SQL查询语句
     * @param pageSize 指定分页大小，如无需分页，请指定为:0
     * @param absPage  指定当前页
     * @return Ls记录信对象.通过该对象可以获取相关记录和分页等信息.
     * @see #ls(Args)
     */
    Pager<Rs> ls(String sql, int pageSize, int absPage);

    /**
     * 根据给定的查询参数返回Ls记录集对象。
     *
     * @param args 查询的条件参数，至少要指定table属性
     * @return Ls记录集对象.通过该对象可以获取当前页记录和分页等信息.
     * @see #ls(String, int, int)
     */
    Pager<Rs> ls(Args args);

    /**
     * 保存Rs对象到底层数据库(即将Rs对象持久化). <br />
     * 　　系统先判断要持久化的对象是否存在脏数据,如果此对象是干净的,将不会做任何操作；
     * 如果对象存在脏数据,会根据其主键确定其是要更新(UPDATE)还是要写入(INSERT),
     * 对于更新(UPDATE)操作,系统会自动忽略非脏数据字段.
     * <br/>　　调用此方法后,该Rs对象将自动被标记为持久化非脏状态.<br /><br />
     * <strong>注意:</strong> <br />
     * 　　从数据库中查询出来的某条记录(即Rs对象)的某个字段被修改了,
     * 但这个字段还没有被回写到数据库中,那么这个字段我们称之为"<strong>脏数据</strong>".
     * 在修改记录的时候, 就是将脏数据更新写入到数据库,而没有被修改过的干净字段则不会写入. <br/>
     * 　　瞬时对象都是脏数据.
     *
     * @param rs 要保存的Rs对象
     */
    void save(Rs rs);

    List<CommentInfo> getTables();

    TableInfo getTableInfo(String table);

    List<EntityInfo> getEntityMeta();

    EntityInfo getEntityMeta(String entity);

    @Transactional
    void exec(String sql, Object... prms);

}
